package domain;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.swing.JOptionPane;

/**
 * Responsible for reading voxel.cvs file and populating a Large4DArray object
 * which is made on the concept of memory mapped file to enable the managing 
 * of a number of map sheets of GeoTOP data in one single file. At this class 
 * collects the heading data from the voxel.csv file and turn them into class
 * attributes.
 * @author kooijmanj1
 *
 */
public class GeotopLarge4DArray {
	
	// class attributes
	private static final int NRMETALINES = 14;	
	private String name; // name of Random Access File (raf)
	private int lineSize; // number of GeoTOP attributes 
	private Large4DArray array;
	// meta data from csv file, including GeoTOP attributes
	private String gridType;
	private String sorting;
	private int nx;
	private int ny;
	private int nz;
	private double xllcenter;
	private double yllcenter;
	private double zllcenter;
	private double dx;
	private double dy;
	private double dz;
	private double nodata_value;
	private String[] attributeNames;
	private String[] attributeTypes;

	// constructor
	public GeotopLarge4DArray(String name){
		this.name = name; 
	}
	
	/**
	 * Read csv file, populates random access file 
	 * using Large4DArray class, sets meta data file 
	 * @param reader
	 * @throws IOException
	 */
	public void populate(BufferedReader reader){
		setMetaData(reader);
		// read voxel data and populate array
		String line = "";
		String path = "C:/Data/GeoTOP/37wOutput/";
		String RANDOM_ACCESS_FILE_NAME  = path + name + ".raf";
		try {
			array = new Large4DArray(RANDOM_ACCESS_FILE_NAME, lineSize,nz,ny,nx);
		}
		catch (IOException e){
			JOptionPane.showMessageDialog(null, "Error creating new raf file");
		}
		Float attributeValue = 0F;
		try {
			String[] lineValues = null;
			for (int x = 0; x < nx; x++){
				for (int y = 0; y < ny; y++){
					for (int z = 0; z< nz ; z++){
						line = reader.readLine();
						for (int attributeNumber = 0 ; attributeNumber < lineSize; attributeNumber++){
							lineValues = line.split(",");
							attributeValue = Float.parseFloat(lineValues[attributeNumber]);
							array.set(attributeNumber, z, y, x, attributeValue);
						}
					}
				}
			}
		}
		catch (IOException e){
			JOptionPane.showMessageDialog(null,"Error reading csv file");
		}
		finally {
			if (reader != null){
				try { reader.close(); }
				catch ( IOException ioe){
					JOptionPane.showMessageDialog(null, "Error closing reader and/or csv file");
				}
			}
		}
	}
	
	

	/**
	 * Write meta data relevant for raf to file 
	 */
	public void writeMetaData(File file){
		PrintWriter writer = null;
		try {
			writer = new PrintWriter(
					new BufferedWriter(
						new FileWriter(file, false)));
			writer.println("gridType," + gridType);
			writer.println("sorting," + sorting);
			writer.println("nx," + nx);
			writer.println("ny," + ny);
			writer.println("nz," + nz);
			writer.println("xllcenter," + xllcenter);
			writer.println("yllcenter," + yllcenter);
			writer.println("zllcenter," + zllcenter);
			writer.println("dx," + dx);
			writer.println("dy," + dy);
			writer.println("dz," + dz);
			writer.println("nodata_value," + nodata_value);
			
			StringBuffer meta = new StringBuffer();
			meta.append("attributeNames,");
			for(String geotopAttribute : attributeNames) {
				meta.append(geotopAttribute + ",");
			}
			int lastCommaIndex = meta.lastIndexOf(",");
			meta.replace(lastCommaIndex, lastCommaIndex+1, "");
			writer.println(meta.toString());
			
			meta = new StringBuffer();
			meta.append("attributeTypes,");			
			for(String attributeType : attributeTypes) {
				meta.append(attributeType + ",");
			}
			lastCommaIndex = meta.lastIndexOf(",");
			meta.replace(lastCommaIndex, lastCommaIndex+1, "");
			writer.println(meta.toString());
			writer.println("lineSize," + lineSize);
			if(writer.checkError()) {
				System.out.println("Error during writing " + file.getName());
			}
		}
		catch (IOException e) {
			JOptionPane.showMessageDialog(null,"Error writing meta data to file");
		}
		finally {
			if ( writer != null){
				writer.close();
			}
		}
	}
	
	/**
	 * The BufferedReader parameter must be the same as in method populate() as 
	 * reading in populate() must continue on the line after the meta data lines.
	 * @param reader 
	 * @throws IOException
	 */
	private void setMetaData(BufferedReader reader){
		String line = ""; // line as read from file
		String[] metaData = new String[NRMETALINES]; // one line in the file is one element of metaData array
		String[] metaDataLine = null; // String array that stores class attribute name and value separately
		// read line and store in metaData line by line
		try {
			for (int lineNumber = 0; line != null && lineNumber < NRMETALINES; lineNumber++){
				line = reader.readLine();
				metaData[lineNumber] = line;
			}
		}
		catch (IOException e){
			JOptionPane.showMessageDialog(null, "Error reading meta data lines from csv file");
		}
		// convert each metaData element in class attribute name and value
		metaDataLine = metaData[0].split(" ",2);
		gridType = metaDataLine[1];
		metaDataLine = metaData[1].split(" ",2);
		sorting = metaDataLine[1]; // dit moet nog naar een werkbare vorm
		metaDataLine = metaData[2].split(" ",2);
		nx = Integer.parseInt(metaDataLine[1]);
		metaDataLine = metaData[3].split(" ", 2);
		ny = Integer.parseInt(metaDataLine[1]);
		metaDataLine = metaData[4].split(" ", 2);
		nz = Integer.parseInt(metaDataLine[1]);
		metaDataLine = metaData[5].split(" ", 2);
		xllcenter = Double.parseDouble(metaDataLine[1]);
		metaDataLine = metaData[6].split(" ", 2);
		yllcenter = Double.parseDouble(metaDataLine[1]);
		metaDataLine = metaData[7].split(" ", 2);
		zllcenter = Double.parseDouble(metaDataLine[1]);
		metaDataLine = metaData[8].split(" ", 2);
		dx = Double.parseDouble(metaDataLine[1]);
		metaDataLine = metaData[9].split(" ", 2);
		dy = Double.parseDouble(metaDataLine[1]);
		metaDataLine = metaData[10].split(" ", 2);
		dz = Double.parseDouble(metaDataLine[1]);
		metaDataLine = metaData[11].split(" ", 2);
		nodata_value = Double.parseDouble(metaDataLine[1]);
		attributeNames = metaData[12].split(",");
		attributeTypes = metaData[13].split(",");
		lineSize = attributeNames.length;
		System.out.println("lineSize = " + lineSize);	
	}
}
